package ge.telasi.tasks.controller;

import ge.telasi.tasks.TaskException;
import ge.telasi.tasks.model.Structure;
import ge.telasi.tasks.model.User;
import ge.telasi.tasks.model.validation.StructureValidator;
import java.util.List;
import javax.persistence.EntityManager;

/**
 * Structure controller.
 *
 * @author dimitri
 */
public class StructureController extends Controller {

    public Structure findStructure(EntityManager em, int id) {
        return em.find(Structure.class, id);
    }

    public List<Structure> getRootStructures(EntityManager em) {
        return em.createNamedQuery("Structure.selectRoot")
                .getResultList();
    }

    public Structure createStructure(EntityManager em, User user, Structure structure) {
        requireAdmin(em, user); // admin privileies required
        new StructureValidator().validateFull(structure);
        Structure parent = null;
        if (structure.getParent() != null) {
            parent = findStructure(em, structure.getParent().getId());
            structure.setParent(parent);
        }
        em.persist(structure);
        if (parent != null) {
            parent.getChildren().add(structure);
        }
        return structure;
    }

    public Structure updateStructure(EntityManager em, User user, Structure structure) {
        requireAdmin(em, user); // admin privileies required
        new StructureValidator().validateFull(structure);
        Structure exst = findStructure(em, structure.getId());
        Structure exstParent = exst.getParent();
        Structure parent = null;
        if (structure.getParent() != null) {
            parent = findStructure(em, structure.getParent().getId());
            if (findLoopReference(parent, structure.getId()) != null) { // checking for illegal parent
                throw new TaskException("loop reference");
            }
            structure.setParent(parent);
        }
        exst.setName(structure.getName());
        exst.setName2(structure.getName2());
        exst.setParent(parent);
        exst.setType(structure.getType());
        if (exstParent != null) {
            exstParent.getChildren().remove(exst);
        }
        if (parent != null) {
            parent.getChildren().add(structure);
        }
        return exst;
    }

    private Structure findLoopReference(Structure structure, long id) {
        if (structure == null || structure.getId() == null) {
            return null;
        }
        if (structure.getId().longValue() == id) {
            return structure;
        }
        return findLoopReference(structure.getParent(), id);
    }

    public void deleteStructure(EntityManager em, User user, Structure structure) {
        requireAdmin(em, user); // admin privileies required
        Structure exst = findStructure(em, structure.getId());
        if (!exst.getChildren().isEmpty()) {
            String key = "StructureController#delete.nonEmptyStructureChildren";
            throw new TaskException(getLocaleManager().getMessage(key));
        }
        int userCount = new UserController().getAnyUserCountInStructure(em, exst.getId());
        if (userCount > 0) {
            String key = "StructureController#delete.nonEmptyUserChildren";
            throw new TaskException(getLocaleManager().getMessage(key));
        }
        if (exst.getParent() != null) {
            exst.getParent().getChildren().remove(exst);
        }
        em.remove(exst);
    }

}
